<!DOCTYPE html>
<html lang=zh>
<head>
    <!-- so meta -->
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="HandheldFriendly" content="True">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <meta name="description" content="4 way to POST dataHTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。其中 POST 一般用来向服务端提交数据，本文主要讨论 POST 提交数据的几种方式。
我们知道，HTTP 协议是以 ASCII 码传输，建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为三">
<meta property="og:type" content="article">
<meta property="og:title" content="四种常见的POST提交数据方式">
<meta property="og:url" content="http://enomineCN.github.io/2016/11/25/4-way-to-post-data/index.html">
<meta property="og:site_name" content="enomine">
<meta property="og:description" content="4 way to POST dataHTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。其中 POST 一般用来向服务端提交数据，本文主要讨论 POST 提交数据的几种方式。
我们知道，HTTP 协议是以 ASCII 码传输，建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为三">
<meta property="og:updated_time" content="2017-04-28T08:27:09.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="四种常见的POST提交数据方式">
<meta name="twitter:description" content="4 way to POST dataHTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。其中 POST 一般用来向服务端提交数据，本文主要讨论 POST 提交数据的几种方式。
我们知道，HTTP 协议是以 ASCII 码传输，建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为三">
    
    
        
          <link rel="shortcut icon" href="/images/favicon.ico">
        
        
          <link rel="icon" type="image/png" href="/images/favicon-192x192.png" sizes="192x192">
        
        
          <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png">
        
    
    <!-- title -->
    <title>四种常见的POST提交数据方式</title>
    <!-- styles -->
    <link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="/lib/meslo-LG/styles.css">
    <link rel="stylesheet" href="/lib/justified-gallery/justifiedGallery.min.css">
    <link rel="stylesheet" href="/css/style.css">
    <!-- rss -->
    
    
    <!-- jquery -->
    <script src="/lib/jquery/jquery.min.js"></script>
</head>

<body>
    
      <div id="header-post">
  <a id="menu-icon" href="#"><i class="fa fa-bars fa-lg"></i></a>
  <span id="menu">
    <span id="nav">
      <ul>
         
          <li><a href="/">Home</a></li>
         
          <li><a href="/about/">About</a></li>
         
          <li><a href="/archives/">Writing</a></li>
         
          <li><a href="http://github.com/enominecn">Projects</a></li>
        
      </ul>
    </span>
    <br/>
    <span id="actions">
      <span id="i-prev" class="info" style="display:none;">Previous post</span>
      <span id="i-next" class="info" style="display:none;">Next post</span>
      <span id="i-top" class="info" style="display:none;">Back to top</span>
      <span id="i-share" class="info" style="display:none;">Share post</span>
      <ul>
        
        <li><a class="icon" href="/2016/11/25/my-ful-stack-steps/"><i class="fa fa-chevron-left" aria-hidden="true" onmouseover='$("#i-prev").toggle();' onmouseout='$("#i-prev").toggle();'></i></a></li>
        
        
        <li><a class="icon" href="/2016/11/21/itertools-gropby-example/"><i class="fa fa-chevron-right" aria-hidden="true" onmouseover='$("#i-next").toggle();' onmouseout='$("#i-next").toggle();'></i></a></li>
        
        <li><a class="icon" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');"><i class="fa fa-chevron-up" aria-hidden="true" onmouseover='$("#i-top").toggle();' onmouseout='$("#i-top").toggle();'></i></a></li>
        <li><a class="icon" href="#"><i class="fa fa-share-alt" aria-hidden="true" onmouseover='$("#i-share").toggle();' onmouseout='$("#i-share").toggle();' onclick='$("#share").toggle();return false;'></i></a></li>
      </ul>
    </span>
    <br/>
    <div id="share" style="display: none">
      <ul>
        <li><a class="icon" href="http://www.facebook.com/sharer.php?u=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/"><i class="fa fa-facebook" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="https://twitter.com/share?url=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/&text=四种常见的POST提交数据方式"><i class="fa fa-twitter" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="http://www.linkedin.com/shareArticle?url=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/&title=四种常见的POST提交数据方式"><i class="fa fa-linkedin" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="https://pinterest.com/pin/create/bookmarklet/?url=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/&is_video=false&description=四种常见的POST提交数据方式"><i class="fa fa-pinterest" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="mailto:?subject=四种常见的POST提交数据方式&body=Check out this article: http://enomineCN.github.io/2016/11/25/4-way-to-post-data/"><i class="fa fa-envelope" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="https://getpocket.com/save?url=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/&title=四种常见的POST提交数据方式"><i class="fa fa-get-pocket" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="http://reddit.com/submit?url=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/&title=四种常见的POST提交数据方式"><i class="fa fa-reddit" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="http://www.stumbleupon.com/submit?url=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/&title=四种常见的POST提交数据方式"><i class="fa fa-stumbleupon" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="http://digg.com/submit?url=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/&title=四种常见的POST提交数据方式"><i class="fa fa-digg" aria-hidden="true"></i></a></li>
        <li><a class="icon" href="http://www.tumblr.com/share/link?url=http://enomineCN.github.io/2016/11/25/4-way-to-post-data/&name=四种常见的POST提交数据方式&description="><i class="fa fa-tumblr" aria-hidden="true"></i></a></li>
      </ul>
    </div>
    <div id="toc">
      <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#4-way-to-POST-data"><span class="toc-number">1.</span> <span class="toc-text">4 way to POST data</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#application-x-www-form-urlencoded"><span class="toc-number">1.0.1.</span> <span class="toc-text">application/x-www-form-urlencoded</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#multipart-form-data"><span class="toc-number">1.0.2.</span> <span class="toc-text">multipart/form-data</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#application-json"><span class="toc-number">1.0.3.</span> <span class="toc-text">application/json</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#text-xml"><span class="toc-number">1.0.4.</span> <span class="toc-text">text/xml</span></a></li></ol></li></ol></li></ol>
    </div>
  </span>
</div>

    
    <div class="content index width mx-auto px2 my4">
        
        <article class="post" itemscope itemtype="http://schema.org/BlogPosting">
  <header>
    
    <h1 class="posttitle" itemprop="name headline">
        四种常见的POST提交数据方式
    </h1>



    <div class="meta">
      <span class="author" itemprop="author" itemscope itemtype="http://schema.org/Person">
        <span itemprop="name">enomine</span>
      </span>
      
    <div class="postdate">
        <time datetime="2016-11-25T06:11:25.000Z" itemprop="datePublished">2016-11-25</time>
    </div>


      
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/POST/">POST</a>, <a class="tag-link" href="/tags/http/">http</a>
    </div>


    </div>
  </header>
  

  <div class="content" itemprop="articleBody">
    <h1 id="4-way-to-POST-data"><a href="#4-way-to-POST-data" class="headerlink" title="4 way to POST data"></a>4 way to POST data</h1><p><a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank" rel="external">HTTP/1.1 协议</a>规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。其中 POST 一般用来向服务端提交数据，本文主要讨论 POST 提交数据的几种方式。</p>
<p>我们知道，HTTP 协议是以 ASCII 码传输，建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为三个部分：状态行、请求头、消息主体。类似于下面这样：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">&lt;method&gt; &lt;request-URL&gt; &lt;version&gt;</div><div class="line">&lt;headers&gt;</div><div class="line"></div><div class="line">&lt;entity-body&gt;</div></pre></td></tr></table></figure>
<p>协议规定 POST 提交的数据必须放在消息主体（entity-body）中，但协议并没有规定数据必须使用什么编码方式。实际上，开发者完全可以自己决定消息主体的格式，只要最后发送的 HTTP 请求满足上面的格式就可以。</p>
<p>但是，数据发送出去，还要服务端解析成功才有意义。一般服务端语言如 php、python 等，以及它们的 framework，都内置了自动解析常见数据格式的功能。服务端通常是根据请求头（headers）中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码，再对主体进行解析。所以说到 POST 提交数据方案，包含了 Content-Type 和消息主体编码方式两部分。下面就正式开始介绍它们。</p>
<h3 id="application-x-www-form-urlencoded"><a href="#application-x-www-form-urlencoded" class="headerlink" title="application/x-www-form-urlencoded"></a>application/x-www-form-urlencoded</h3><p>这应该是最常见的 POST 提交数据的方式了。浏览器的原生 &lt;form&gt; 表单，如果不设置 <code>enctype</code> 属性，那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样（无关的请求头在本文中都省略掉了）：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">POST http://www.example.com HTTP/1.1</div><div class="line">Content-Type: application/x-www-form-urlencoded;charset=utf-8</div><div class="line"></div><div class="line">title=<span class="built_in">test</span>&amp;sub%5B%5D=1&amp;sub%5B%5D=2&amp;sub%5B%5D=3</div></pre></td></tr></table></figure>
<p>首先，Content-Type 被指定为 application/x-www-form-urlencoded；其次，提交的数据按照 key1=val1&amp;key2=val2 的方式进行编码，key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。例如 PHP 中，$_POST[‘title’] 可以获取到 title 的值，$_POST[‘sub’] 可以得到 sub 数组。</p>
<p>很多时候，我们用 Ajax 提交数据时，也是使用这种方式。例如 <a href="http://jquery.com/" target="_blank" rel="external">JQuery</a> 和 <a href="http://www.qwrap.com" target="_blank" rel="external">QWrap</a> 的 Ajax，Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。</p>
<h3 id="multipart-form-data"><a href="#multipart-form-data" class="headerlink" title="multipart/form-data"></a>multipart/form-data</h3><p>这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时，必须让 &lt;form&gt; 表单的 <code>enctype</code> 等于 multipart/form-data。直接来看一个请求示例：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">POST http://www.example.com HTTP/1.1</div><div class="line">Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA</div><div class="line"></div><div class="line">------WebKitFormBoundaryrGKCBY7qhFd3TrwA</div><div class="line">Content-Disposition: form-data; name=<span class="string">"text"</span></div><div class="line"></div><div class="line">title</div><div class="line">------WebKitFormBoundaryrGKCBY7qhFd3TrwA</div><div class="line">Content-Disposition: form-data; name=<span class="string">"file"</span>; filename=<span class="string">"chrome.png"</span></div><div class="line">Content-Type: image/png</div><div class="line"></div><div class="line">PNG ... content of chrome.png ...</div><div class="line">------WebKitFormBoundaryrGKCBY7qhFd3TrwA--</div></pre></td></tr></table></figure>
<p>这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段，为了避免与正文内容重复，boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码，本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分，每部分都是以 <code>--boundary</code> 开始，紧接着是内容描述信息，然后是回车，最后是字段具体内容（文本或二进制）。如果传输的是文件，还要包含文件名和文件类型信息。消息主体最后以 <code>--boundary--</code> 标示结束。关于 multipart/form-data 的详细定义，请前往 <a href="http://www.ietf.org/rfc/rfc1867.txt" target="_blank" rel="external">rfc1867</a> 查看。</p>
<p>这种方式一般用来上传文件，各大服务端语言对它也有着良好的支持。</p>
<p>上面提到的这两种 POST 数据的方式，都是浏览器原生支持的，而且现阶段标准中原生 &lt;form&gt; 表单也<a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4" target="_blank" rel="external">只支持这两种方式</a>（通过 &lt;form&gt; 元素的 <code>enctype</code> 属性指定，默认为 <code>application/x-www-form-urlencoded</code>。其实 <code>enctype</code> 还支持 <code>text/plain</code>，不过用得非常少）。</p>
<p>随着越来越多的 Web 站点，尤其是 WebApp，全部使用 Ajax 进行数据交互之后，我们完全可以定义新的数据提交方式，给开发带来更多便利。</p>
<h3 id="application-json"><a href="#application-json" class="headerlink" title="application/json"></a>application/json</h3><p>application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上，现在越来越多的人把它作为请求头，用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行，除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify，服务端语言也都有处理 JSON 的函数，使用 JSON 不会遇上什么麻烦。</p>
<p>JSON 格式支持比键值对复杂得多的结构化数据，这一点也很有用。记得我几年前做一个项目时，需要提交的数据层次非常深，我就是把数据 JSON 序列化之后来提交的。不过当时我是把 JSON 字符串作为 val，仍然放在键值对里，以 x-www-form-urlencoded 方式提交。</p>
<p>Google 的 <a href="http://angularjs.org" target="_blank" rel="external">AngularJS</a> 中的 Ajax 功能，默认就是提交 JSON 字符串。例如下面这段代码：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> data = &#123;<span class="string">'title'</span>:<span class="string">'test'</span>, <span class="string">'sub'</span> : [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]&#125;;</div><div class="line">$http.post(url, data).success(<span class="function"><span class="keyword">function</span>(<span class="params">result</span>) </span>&#123;</div><div class="line">	...</div><div class="line">&#125;);</div></pre></td></tr></table></figure>
<p>最终发送的请求是：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">POST http://www.example.com HTTP/1.1 </div><div class="line">Content-Type: application/json;charset=utf-8</div><div class="line"></div><div class="line">&#123;<span class="string">"title"</span>:<span class="string">"test"</span>,<span class="string">"sub"</span>:[1,2,3]&#125;</div></pre></td></tr></table></figure>
<p>这种方案，可以方便的提交复杂的结构化数据，特别适合 RESTful 的接口。各大抓包工具如 Chrome 自带的开发者工具、Firebug、Fiddler，都会以树形结构展示 JSON 数据，非常友好。但也有些服务端语言还没有支持这种方式，例如 php 就无法通过 $_POST 对象从上面的请求中获得内容。这时候，需要自己动手处理下：在请求头中 Content-Type 为 application/json 时，从 <code>php://input</code> 里获得原始输入流，再 <code>json_decode</code> 成对象。一些 php 框架已经开始这么做了。</p>
<p>当然 AngularJS 也可以配置为使用 x-www-form-urlencoded 方式提交数据。如有需要，可以参考<a href="http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/" target="_blank" rel="external">这篇文章</a>。</p>
<h3 id="text-xml"><a href="#text-xml" class="headerlink" title="text/xml"></a>text/xml</h3><p>我的博客之前<a href="http://www.imququ.com/post/64.html" target="_blank" rel="external">提到过 XML-RPC</a>（XML Remote Procedure Call）。它是一种使用 HTTP 作为传输协议，XML 作为编码方式的远程调用规范。典型的 XML-RPC 请求是这样的：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">POST http://www.example.com HTTP/1.1 </div><div class="line">Content-Type: text/xml</div><div class="line"></div><div class="line">&lt;?xml version="1.0"?&gt;</div><div class="line"><span class="tag">&lt;<span class="name">methodCall</span>&gt;</span></div><div class="line">	<span class="tag">&lt;<span class="name">methodName</span>&gt;</span>examples.getStateName<span class="tag">&lt;/<span class="name">methodName</span>&gt;</span></div><div class="line">	<span class="tag">&lt;<span class="name">params</span>&gt;</span></div><div class="line">		<span class="tag">&lt;<span class="name">param</span>&gt;</span></div><div class="line">			<span class="tag">&lt;<span class="name">value</span>&gt;</span><span class="tag">&lt;<span class="name">i4</span>&gt;</span>41<span class="tag">&lt;/<span class="name">i4</span>&gt;</span><span class="tag">&lt;/<span class="name">value</span>&gt;</span></div><div class="line">		<span class="tag">&lt;/<span class="name">param</span>&gt;</span></div><div class="line">	<span class="tag">&lt;/<span class="name">params</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">methodCall</span>&gt;</span></div></pre></td></tr></table></figure>
<p>XML-RPC 协议简单、功能够用，各种语言的实现都有。它的使用也很广泛，如 WordPress 的 <a href="http://codex.wordpress.org/XML-RPC_WordPress_API" target="_blank" rel="external">XML-RPC Api</a>，搜索引擎的 <a href="http://help.baidu.com/question?prod_en=master&amp;class=476&amp;id=1000423" target="_blank" rel="external">ping 服务</a>等等。JavaScript 中，也有<a href="http://plugins.jquery.com/xmlrpc/" target="_blank" rel="external">现成的库</a>支持以这种方式进行数据交互，能很好的支持已有的 XML-RPC 服务。不过，我个人觉得 XML 结构还是过于臃肿，一般场景用 JSON 会更灵活方便。</p>
<p>原文链接：<a href="https://imququ.com/post/four-ways-to-post-data-in-http.html" target="_blank" rel="external">https://imququ.com/post/four-ways-to-post-data-in-http.html</a>，<a href="https://imququ.com/post/four-ways-to-post-data-in-http.html#comments" target="_blank" rel="external">前往原文评论 »</a></p>

  </div>
</article>



      </div>
    <footer id="footer">
  <div class="footer-left">
    Copyright &copy; 2017 enomine
  </div>
  <div class="footer-right">
    <nav>
      <ul>
         
          <li><a href="/">Home</a></li>
         
          <li><a href="/about/">About</a></li>
         
          <li><a href="/archives/">Writing</a></li>
         
          <li><a href="http://github.com/enominecn">Projects</a></li>
        
      </ul>
    </nav>
  </div>
</footer>

    <script src="/lib/justified-gallery/jquery.justifiedGallery.min.js"></script>
<script src="/js/main.js"></script>
<!-- Google Analytics -->

    <script type="text/javascript">
        (function(i,s,o,g,r,a,m) {i['GoogleAnalyticsObject']=r;i[r]=i[r]||function() {
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
        ga('create', 'UA-86660611-1', 'auto');
        ga('send', 'pageview');
    </script>

<!-- Disqus Comments -->


</body>
</html>
